// ==UserScript==
// @name         下载 Fanbox文件
// @namespace    http://tampermonkey.net/
// @version      0.0.1-2025-03-31
// @description  暂时仅支持公开作品
// @match        https://www.fanbox.cc/*/posts/*
// @icon         https://s.pximg.net/common/images/fanbox/favicon.ico
// @grant        GM_xmlhttpRequest
// @connect      api.fanbox.cc
// @connect      localhost
// @author       AgMonk
// @homepage     https://gitee.com/AgMonk/tampermonkey-script
// @downloadURL https://gitee.com/AgMonk/tampermonkey-script/raw/master/fanbox/fanbox-download.user.js
// @updateURL https://gitee.com/AgMonk/tampermonkey-script/raw/master/fanbox/fanbox-download.user.js

// ==/UserScript==

(function (url, body) {
    // 运行参数，可以 localStorage.setItem 方法填入对应KEY修改

    // rpcUrl的KEY和默认值
    const RPC_URL_KEY = "RPC_URL";
    const DEFAULT_RPC_URL = "http://localhost:6800/jsonrpc";

    // 代理服务器IP端口的KEY和默认值
    const HTTPS_PROXY_KEY = "HTTPS_PROXY";
    const DEFAULT_HTTPS_PROXY = "127.0.0.1:10809";

    // 下载目录的KEY和默认值
    const DOWNLOAD_DIR_KEY = "DOWNLOAD_DIR";
    const DEFAULT_DOWNLOAD_DIR = "d:/fanbox";


    // 从localStorage中获取运行参数，如果为空则取默认值
    const getValue = (key, defaultValue) => {
        const value = localStorage.getItem(key)
        return value ? value : defaultValue
    }

    const getProxy = () => getValue(HTTPS_PROXY_KEY, DEFAULT_HTTPS_PROXY)

    const getRpcUrl = () => getValue(RPC_URL_KEY, DEFAULT_RPC_URL)
    /**
     * 构造单个下载参数
     */
    const buildAddUriParam = (url, dir, filename,) => {
        return {
            methodName: "aria2.addUri",
            params: [
                [url],
                {
                    dir: dir,
                    "https-proxy": getProxy(),
                    "out": filename,
                },
                0
            ]
        }
    }

    /**
     * 封装POST请求方法
     * @param url 请求地址
     * @param body
     * @returns {Promise<unknown>}
     */
    async function postData(url, body) {
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: 'POST',
                url: url,
                headers: {
                    "Content-Type": "application/json"
                },
                data: JSON.stringify(body),
                onload: function (response) {
                    try {
                        let data = JSON.parse(response.responseText);
                        resolve(data); // 请求成功，解决 Promise
                    } catch (error) {
                        reject(error); // 解析 JSON 失败，拒绝 Promise
                    }
                },
                onerror: function (error) {
                    reject(error); // 请求失败，拒绝 Promise
                }
            });
        });
    }


    /**
     * 提交多个下载任务
     * @param params 下载任务参数列表
     * @returns {Promise<*>}
     */
    async function addDownloadTasks(params) {
        let body = {jsonrpc: '2.0', id: new Date().getTime().toString(), method: 'system.multicall', params: [params]};
        console.log(body)
        return postData(getRpcUrl(), body)
    }

    // 查询作品信息
    async function postInfo(id) {
        // https://api.fanbox.cc/post.info?postId=7924911
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: 'GET',
                url: "https://api.fanbox.cc/post.info?postId=" + id,
                headers: {
                    "origin": "https://www.fanbox.cc",
                    "referer": "https://www.fanbox.cc",
                },
                onload: function (response) {
                    try {
                        let data = JSON.parse(response.responseText);
                        resolve(data.body); // 请求成功，解决 Promise
                    } catch (error) {
                        reject(error); // 解析 JSON 失败，拒绝 Promise
                    }
                },
                onerror: function (error) {
                    reject(error); // 请求失败，拒绝 Promise
                }
            });
        });
    }

    async function downloadAll() {
        const res = await postInfo(window.location.href.split("/").pop());
        const files = res.body.files

        const date = new Date(res.publishedDatetime).toLocaleDateString().replace(/\//g,'-')
        const dir = getValue(DOWNLOAD_DIR_KEY, DEFAULT_DOWNLOAD_DIR)
            +`/${res.creatorId}_${res.user.name}/[${res.id}][${date}] ${res.title}`
        console.log('[Fanbox] 文件',files)

        // aria2请求的参数
        const params = files.map(file=>{
            const filename=  `${file.name}.${file.extension}`
            const url = file.url
            return buildAddUriParam(url, dir, filename)
        })

        console.log('[Fanbox] 下载参数',params)
        let {result} = await addDownloadTasks(params);
        let gid = result.flatMap(i => i)
        console.log(gid)
        alert(`已提交 ${params.length} 个下载任务`)
    }


    console.log("aria2检查开始")
    // 循环执行
    setInterval(() => {
        const id = 'download_all_button'
        const h1 = document.querySelector('article h1')
        if (!document.getElementById(id) && h1) {
            let button = document.createElement('button');
            button.innerText = '下载全部';
            button.id = id
            button.onclick = ()=>downloadAll()
            h1.parentElement.appendChild(button)
        }
    }, 200)
})();
